/*
 * JBoss, Home of Professional Open Source
 * Copyright 2010, Red Hat Middleware LLC, and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.slaffka;

import com.slaffka.model.Filial;
import com.slaffka.model.Role;
import com.slaffka.model.RoleType;
import com.slaffka.model.User;
import org.jboss.solder.logging.Logger;
import org.jboss.solder.servlet.WebApplication;
import org.jboss.solder.servlet.event.Initialized;

import javax.enterprise.event.Observes;
import javax.enterprise.inject.Alternative;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.transaction.Status;
import javax.transaction.UserTransaction;
import javax.validation.ConstraintViolationException;
import java.util.*;

/**
 * An alternative bean used to import seed data into the database when the application is being initialized.
 *
 * @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
 * @author <a href="http://community.jboss.org/people/dan.j.allen">Dan Allen</a>
 */
// @Stateless // can't use EJB since they are not yet available for lookup when initialized event is fired
@Alternative
public class ApplicationInitializer {
    @PersistenceContext
    private EntityManager entityManager;

    @Inject
    private UserTransaction utx;

    @Inject
    private Logger log;

    private final List<User> users = new ArrayList<User>();
    private final List<Filial> filialList = new ArrayList<Filial>();

    public ApplicationInitializer() {
        Filial filialSamara = new Filial("samara", "Самара", 100000d);
        Filial filialPriv = new Filial("privolzhe", "Приволжье", 50000d);
        Filial filialNeftegorsk = new Filial("neftegorsk", "Нефтегорск", 100000d);

        Double sumAmount = filialSamara.getCapital() + filialNeftegorsk.getCapital() + filialPriv.getCapital();
        Filial multiFilial = new Filial("multiFilial", "Мультифилиал", sumAmount);

        filialList.add(multiFilial);
        filialList.add(filialNeftegorsk);
        filialList.add(filialPriv);
        filialList.add(filialSamara);

        Set<Role> roles = new HashSet<Role>();
        Role adminRole = new Role(RoleType.ADMIN);
        roles.add(adminRole);

        users.addAll(Arrays.asList(
                new User("slaffka", "slaffka1", multiFilial, roles),
                new User("samara", "1", filialSamara)));


    }

    /**
     * Import seed data when Seam Servlet fires an event notifying observers that the web application is being initialized.
     */
    public void importData(@Observes @Initialized WebApplication webapp) {
        log.info("Importing seed data for application " + webapp.getName());
        // use manual transaction control since this is a managed bean
        try {
            utx.begin();
            // AS7-2045
            entityManager.createQuery("delete from Filial").executeUpdate();
            entityManager.createQuery("delete from User").executeUpdate();
            persist(filialList);
            persist(users);
            utx.commit();
            log.info("Seed data successfully imported");
        } catch (Exception e) {
            log.error("Import failed. Seed data will not be available.", e);
            try {
                if (utx.getStatus() == Status.STATUS_ACTIVE) {
                    try {
                        utx.rollback();
                    } catch (Exception rbe) {
                        log.error("Error rolling back transaction", rbe);
                    }
                }
            } catch (Exception se) {
            }
        }
    }

    private void persist(List<?> entities) {
        for (Object e : entities) {
            persist(e);
        }
    }

    private void persist(Object entity) {
        // use a try-catch block here so we can capture identity
        // of entity that fails to persist
        try {
            entityManager.persist(entity);
            entityManager.flush();
        } catch (ConstraintViolationException e) {
            throw new PersistenceException("Cannot persist invalid entity: " + entity);
        } catch (PersistenceException e) {
            throw new PersistenceException("Error persisting entity: " + entity, e);
        }
    }
}
